package LibDL.recommender;

import LibDL.recommender.data.utils.NumUtils;
import LibDL.recommender.data.model.TextSequenceDataModel;
import LibDL.recommender.utils.RecommenderUtils;
import net.librec.common.LibrecException;
import net.librec.math.structure.*;

import java.util.ArrayList;
import java.util.HashMap;

public abstract class SequencialRecommender extends LibDLRecommender {

    protected int L;

    protected int T;

    protected int neg_samples;

    protected HashMap<Integer, ArrayList<Integer>> candidate;

    @Override
    protected void setup() throws LibrecException {
        super.setup();
        L = conf.getInt("libdl.sequence.length", 5);
        T = conf.getInt("libdl.sequence.target", 3);
        neg_samples = conf.getInt("libdl.sequence.negative", 3);
        candidate = new HashMap<>();
        num_users = ((TextSequenceDataModel) context.getDataModel()).getTrainSequence().num_users;
        num_items = ((TextSequenceDataModel) context.getDataModel()).getTrainSequence().num_items;
    }

    protected void generate_candidate() {
        if (this.candidate.size() == 0) {
            long t1 = System.currentTimeMillis();
            ArrayList<Integer> all_items_ = (ArrayList<Integer>) NumUtils.arange(1, num_items, 1);
            SequentialAccessSparseMatrix train = (SequentialAccessSparseMatrix) this.getDataModel().getTrainDataSet();
            for (int user = 0; user < train.rowSize(); user++) {
                VectorBasedSequentialSparseVector row = (VectorBasedSequentialSparseVector) train.row(user);
                ArrayList<Integer> all_items = new ArrayList<>(all_items_);
                int[] i_ = row.getIndices();
                for (int value : i_) {
                    all_items.remove((Object) value);
                }
                this.candidate.put(user, all_items);
            }
            String out = String.format("Generate candidate [%.2f s]", (float)(System.currentTimeMillis() - t1) / 1000);
            LOG.info(out);
        }
    }

    protected DenseMatrix generate_negative_samples(DenseMatrix users, int n) {

        assert users.columnSize() == 1;
        DenseVector users_ = users.column(0);
        DenseMatrix negative_samples = new DenseMatrix(users_.size(), n);
        generate_candidate();

        for (int i = 0; i < users_.size(); i++) {
            int u = (int) users_.get(i);
            for (int j = 0; j < n; j++) {
                ArrayList<Integer> x = this.candidate.get(u);
                // negative_samples[i, j] = x[np.random.randint(len(x))]
                long value = x.get(RecommenderUtils.random.nextInt(x.size()));
                negative_samples.set(i, j, (double) value);
            }
        }

        return negative_samples;
    }
}
